
import requests
import traceback
import time
import config
from apps.cms.models import CaseManage
from .getLogs import collectLogs
from .commonFunc import is_headers_ok, get_headers, myReplace
from .restful import restful_result
import json
import emoji

# 定义全局变量，特殊说明：runCode=0表示用例未执行，runCode=1表示用例断言成功，runCode=9表示用例断言失败。
data = {}
run_res = {'runCode': 0, 'data':data, 'message':'用例未执行'}
requestTimeout = config.requestTimeout

# 单用例执行，传参为case对象
def runCase_single(case):
    if not case:
        run_res['runCode'] = 2
        run_res['message'] = '执行用例的传参对象不能为空！'
        data['case'] = case
        data['caseName'] = '用例为空：%s' %(case,)
        data['method'] = '无'
        data['casePath'] = '无'
        data['caseParam'] = '无'
        data['expect_res'] = '无'
        data['duration'] = '0ms'
        data['httpCode'] = 0
        data['runRes'] = '无'
        collectLogs(loginfo=run_res, lever='error', logger='runCase_single')
        return run_res
    if not isinstance(case, CaseManage):
        run_res['runCode'] = 3
        run_res['message'] = 'runCase_single执行用例的传参类型必须是CaseManage对象！'
        # data['case'] = case
        # data['type'] = type(case)
        data['caseName'] = '用例类型错误：%s-%s' %(case, str(type(case)))
        data['method'] = '无'
        data['casePath'] = '无'
        data['caseParam'] = '无'
        data['expect_res'] = '无'
        data['duration'] = '0ms'
        data['httpCode'] = 0
        data['runRes'] = '无'
        collectLogs(loginfo=run_res, lever='error', logger='runCase_single')
        return run_res
    method = case.request_method
    casePath = case.case_path
    caseParam = case.case_parm
    headers = get_headers(case.headers)
    case_name = case.case_name
    expect_res = case.expect_res
    expect_res_tem = str(expect_res)
    try:
        s = requests.session()
        s.keep_alive = False
        collectLogs(loginfo='用例【%s】开始执行...' % case_name, lever='info', logger='runCase_single')
        startRun = time.time()
        if str(method).lower() == 'post':
            if (str(caseParam[:5]).lower() + str(caseParam[-1:]).lower()) == 'json()':
                caseParam = json.dumps(caseParam[5:-1])
            else:
                caseParam = str(caseParam)
            response = requests.request('POST', url=casePath, data=caseParam.encode('utf-8'), headers=headers, timeout=requestTimeout)
        else:
            response = requests.request('GET', casePath, params=str(caseParam), headers=headers, timeout=requestTimeout)
        endRun = time.time()
        duration = round((endRun - startRun) * 1000)
        responseText = emoji.demojize(response.text)
        expect_res_list = expect_res_tem.split('=')
        assertType = ''
        if len(expect_res_list) > 1:
            assertType = expect_res_list[0].lower()
            if assertType in ['or', 'and', 'not']:
                expect_res_tem = myReplace(expect_res_tem, expect_res_list[0] + '=', '', -1, '1')
        if assertion(expect_res_tem, responseText, assertType):
            run_res['runCode'] = 1
            run_res['message'] = '用例执行结束，预期结果匹配成功！'
            data['caseName'] = case_name
            data['method'] = method
            data['casePath'] = casePath
            data['caseParam'] = caseParam
            data['expect_res'] = expect_res
            data['duration'] = '%dms' % duration
            data['httpCode'] = response.status_code
            data['runRes'] = responseText
        else:
            run_res['runCode'] = 9
            run_res['message'] = '用例执行结束，预期结果匹配失败！'
            data['caseName'] = case_name
            data['method'] = method
            data['casePath'] = casePath
            data['caseParam'] = caseParam
            data['expect_res'] = expect_res
            data['duration'] = '%dms' % duration
            data['httpCode'] = response.status_code
            data['runRes'] = responseText
        collectLogs(loginfo='执行信息：%s' %run_res, lever='info', logger='runCase_single')
        collectLogs(loginfo='用例【%s】执行结束！' % case_name, lever='info', logger='runCase_single')
        return run_res
    except Exception as e:
        run_res['runCode'] = 4
        run_res['message'] = '用例执行遇到异常，请查看日志！'
        data['caseName'] = case_name
        data['method'] = method
        data['casePath'] = casePath
        data['caseParam'] = caseParam
        data['expect_res'] = expect_res
        data['duration'] = '0ms'
        data['httpCode'] = 0
        data['runRes'] = '用例执行异常：%s' %(e, )
        collectLogs(loginfo='执行信息：%s' %run_res, lever='error', logger='runCase_single')
        collectLogs(loginfo='用例【%s】执行遇到异常，原因：%s' %(case_name, traceback.format_exc()), lever='error', logger='runCase_single')
        return run_res


# 单用例执行，传参为用例元组
def runOneCase(case):
    if not case:
        run_res['runCode'] = 2
        run_res['message'] = '执行用例的传参对象不能为空！'
        data['case'] = case
        data['caseName'] = '用例为空：%s' %(case,)
        data['method'] = '无'
        data['casePath'] = '无'
        data['caseParam'] = '无'
        data['expect_res'] = '无'
        data['duration'] = '0ms'
        data['httpCode'] = 0
        data['runRes'] = '无'
        collectLogs(loginfo=run_res, lever='error', logger='runOneCase')
        return run_res
    if not isinstance(case, tuple):
        run_res['runCode'] = 3
        run_res['message'] = 'runOneCase执行用例的传参类型必须是tuple类型！'
        # data['case'] = case
        # data['type'] = type(case)
        data['caseName'] = '用例类型错误：%s-%s' %(case, str(type(case)))
        data['method'] = '无'
        data['casePath'] = '无'
        data['caseParam'] = '无'
        data['expect_res'] = '无'
        data['duration'] = '0ms'
        data['httpCode'] = 0
        data['runRes'] = '无'
        collectLogs(loginfo=run_res, lever='error', logger='runOneCase')
        return run_res
    method = case[5]
    casePath = case[3]
    caseParam = case[4]
    headers = get_headers(case[7])
    case_name = case[1]
    expect_res = case[6]
    expect_res_tem = str(expect_res)
    try:
        s = requests.session()
        s.keep_alive = False
        collectLogs(loginfo='用例【%s】开始执行...' % case_name, lever='info', logger='runOneCase')
        startRun = time.time()
        if str(method).lower() == 'post':
            if (str(caseParam[:5]).lower() + str(caseParam[-1:]).lower()) == 'json()':
                caseParam = json.dumps(caseParam[5:-1])
            else:
                caseParam = str(caseParam)
            response = requests.request('POST', url=casePath, data=caseParam.encode('utf-8'), headers=headers, timeout=requestTimeout)
        else:
            response = requests.request('GET', casePath, params=str(caseParam), headers=headers, timeout=requestTimeout)
        endRun = time.time()
        duration = round((endRun - startRun) * 1000)
        responseText = emoji.demojize(response.text)
        expect_res_list = expect_res_tem.split('=')
        assertType = ''
        if len(expect_res_list) > 1:
            assertType = expect_res_list[0].lower()
            if assertType in ['or', 'and', 'not']:
                expect_res_tem = myReplace(expect_res_tem, expect_res_list[0] + '=', '', -1, '1')
        if assertion(expect_res_tem, responseText, assertType):
            run_res['runCode'] = 1
            run_res['message'] = '用例执行结束，预期结果匹配成功！'
            data['caseName'] = case_name
            data['method'] = method
            data['casePath'] = casePath
            data['caseParam'] = caseParam
            data['expect_res'] = expect_res
            data['duration'] = '%dms' % duration
            data['httpCode'] = response.status_code
            data['runRes'] = responseText
        else:
            run_res['runCode'] = 9
            run_res['message'] = '用例执行结束，预期结果匹配失败！'
            data['caseName'] = case_name
            data['method'] = method
            data['casePath'] = casePath
            data['caseParam'] = caseParam
            data['expect_res'] = expect_res
            data['duration'] = '%dms' % duration
            data['httpCode'] = response.status_code
            data['runRes'] = responseText
        collectLogs(loginfo='执行信息：%s' %run_res, lever='info', logger='runOneCase')
        collectLogs(loginfo='用例【%s】执行结束！' % case_name, lever='info', logger='runOneCase')
        return run_res
    except Exception as e:
        run_res['runCode'] = 4
        run_res['message'] = '用例执行遇到异常，请查看日志！'
        data['caseName'] = case_name
        data['method'] = method
        data['casePath'] = casePath
        data['caseParam'] = caseParam
        data['expect_res'] = expect_res
        data['duration'] = '0ms'
        data['httpCode'] = 0
        data['runRes'] = '用例执行异常：%s' %(e, )
        collectLogs(loginfo='执行信息：%s' %run_res, lever='error', logger='runOneCase')
        collectLogs(loginfo='用例【%s】执行遇到异常，原因：%s' %(case_name, traceback.format_exc()), lever='error', logger='runOneCase')
        return run_res


# 调试用例
def debugCaseFunc(method, casePath, caseParam, headers, expect_res, case_name):
    expect_res_tem = str(expect_res)
    if not method or not casePath or not expect_res:
        run_res['runCode'] = 2
        run_res['message'] = '调试用例的传参不能为空！'
        data['caseName'] = case_name
        data['method'] = method
        data['casePath'] = casePath
        data['caseParam'] = caseParam
        data['expect_res'] = expect_res
        data['duration'] = '0ms'
        data['httpCode'] = 0
        data['runRes'] = '用例信息获取不全，无法调试'
        collectLogs(loginfo=run_res, lever='error', logger='debugCaseFunc')
        return run_res
    try:
        s = requests.session()
        s.keep_alive = False
        collectLogs(loginfo='用例【%s】开始调试...' % case_name, lever='info', logger='debugCaseFunc')
        startRun = time.time()

        headers = get_headers(headers)
        if str(method).lower() == 'post':
            if (str(caseParam[:5]).lower() + str(caseParam[-1:]).lower()) == 'json()':
                caseParam = json.dumps(caseParam[5:-1])
            else:
                caseParam = str(caseParam)
            response = requests.request('POST', url=casePath, data=caseParam.encode('utf-8'), headers=headers, timeout=requestTimeout)
        else:
            response = requests.request('GET', url=casePath, params=caseParam, headers=headers, timeout=requestTimeout)
        endRun = time.time()
        duration = round((endRun - startRun) * 1000)
        responseText = emoji.demojize(response.text)
        expect_res_list = expect_res_tem.split('=')
        assertType = ''
        if len(expect_res_list) > 1:
            assertType = expect_res_list[0].lower()
            if assertType in ['or', 'and', 'not']:
                expect_res_tem = myReplace(expect_res_tem, expect_res_list[0] + '=', '', -1, '1')
                # expect_res = ''.join(expect_res_list[1:]) # 该方式会将第2个及以后的等号给去掉（如果出现断言结果中有等号的情况）

        if assertion(expect_res_tem, responseText, assertType):
            run_res['runCode'] = 1
            run_res['message'] = '用例调试结束，预期结果匹配成功！'
            data['caseName'] = case_name
            data['headers'] = headers
            data['method'] = method
            data['casePath'] = casePath
            data['caseParam'] = caseParam
            data['expect_res'] = expect_res
            data['duration'] = '%dms' %duration
            data['httpCode'] = response.status_code
            data['runRes'] = responseText
        else:
            run_res['runCode'] = 9
            run_res['message'] = '用例调试结束，预期结果匹配失败！'
            data['caseName'] = case_name
            data['headers'] = headers
            data['responseHeaders'] = response.headers
            data['method'] = method
            data['casePath'] = casePath
            data['caseParam'] = caseParam
            data['expect_res'] = expect_res
            data['duration'] = '%dms' % duration
            data['httpCode'] = response.status_code
            data['runRes'] = responseText
        collectLogs(loginfo='调试信息：%s' %run_res, lever='info', logger='debugCaseFunc')
        collectLogs(loginfo='用例【%s】调试结束！' % case_name, lever='info', logger='debugCaseFunc')
        return run_res
    except Exception as e:
        run_res['runCode'] = 4
        run_res['message'] = '用例调试遇到异常，请查看日志！'
        data['caseName'] = case_name
        data['method'] = method
        data['casePath'] = casePath
        data['caseParam'] = caseParam
        data['expect_res'] = expect_res
        data['duration'] = '0ms'
        data['httpCode'] = 0
        data['runRes'] = '用例调试异常：%s' %(e, )
        collectLogs(loginfo='调试信息：%s' %run_res, lever='error', logger='debugCaseFunc')
        collectLogs(loginfo='用例【%s】调试遇到异常，原因：%s' %(case_name, traceback.format_exc()), lever='error', logger='debugCaseFunc')
        return run_res

# 断言：模糊匹配、逻辑or匹配、逻辑and匹配、逻辑not匹配
def assertion(expect, response, assertType=''):
    try:
        expect = str(expect).strip('$')
        expectList = expect.split('$')
        response = str(response)
        assertType = str(assertType).lower()
        expectItemNum = len(expectList)
        if expectItemNum < 2:
            if assertType != 'not':
                if expectList[0] in response:
                    return True
                else:
                    return False
            else:
                if expectList[0] not in response:
                    return True
                else:
                    return False

        else:
            if assertType == 'or':
                for item in expectList:
                    if item in response:
                        return True

            elif assertType == 'and':
                temSet = set()
                for item in expectList:
                    if item in response:
                        temSet.add('1')
                    else:
                        temSet.add('0')
                if '0' in temSet:
                    return False
                else:
                    return True

            elif assertType == 'not':
                temSet = set()
                for item in expectList:
                    if item in response:
                        temSet.add('0')
                    else:
                        temSet.add('1')
                if '0' in temSet:
                    return False
                else:
                    return True

            # 如果格式不正确，则默认取第一个预期结果为断言依据
            else:
                if expectList[0] in response:
                    return True
                else:
                    return False
    except Exception:
        collectLogs(loginfo='断言遇到异常，原因：%s' % (traceback.format_exc()), lever='error', logger='assertion')
